/*
 * Copyright(c) 2020-2100 万达信息股份有限公司 版权所有
 * WONDERS INFORMATION CO., LTD. ALL RIGHTS RESERVED.
 */

package com.wondersgroup.sqlengine.script;

import java.io.StringReader;
import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Member;
import java.lang.reflect.Modifier;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import ognl.*;

/**
 * 表达式缓存
 *
 * @author: huym
 * @date: 2021/1/22
 */
public class OgnlCache {

	private static final Map<String, ognl.Node> expressionCache = new ConcurrentHashMap();

	private static final OgnlContext context = new OgnlContext(null,null, new DefaultMemberAccess(true));

	public static Object getValue(String expression, Object root) {
		try {
			return Ognl.getValue(parseExpression(expression), context, root);
		} catch (OgnlException e) {
			throw new RuntimeException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
		}
	}

	private static Object parseExpression(String expression) throws OgnlException {
		try {
			Node node = expressionCache.get(expression);
			if (node == null) {
				node = new OgnlParser(new StringReader(expression)).topLevelExpression();
				expressionCache.put(expression, node);
			}
			return node;
		} catch (ParseException e) {
			throw new ExpressionSyntaxException(expression, e);
		} catch (TokenMgrError e) {
			throw new ExpressionSyntaxException(expression, e);
		}
	}

	static class DefaultMemberAccess implements MemberAccess {

		public boolean allowPrivateAccess;

		public boolean allowProtectedAccess;

		public boolean allowPackageProtectedAccess;

		public DefaultMemberAccess(boolean allowAllAccess) {
			this(allowAllAccess, allowAllAccess, allowAllAccess);
		}

		public DefaultMemberAccess(boolean allowPrivateAccess, boolean allowProtectedAccess, boolean allowPackageProtectedAccess) {
			super();
			this.allowPrivateAccess = allowPrivateAccess;
			this.allowProtectedAccess = allowProtectedAccess;
			this.allowPackageProtectedAccess = allowPackageProtectedAccess;
		}

		public boolean getAllowPrivateAccess() {
			return allowPrivateAccess;
		}

		public boolean getAllowProtectedAccess() {
			return allowProtectedAccess;
		}

		public boolean getAllowPackageProtectedAccess() {
			return allowPackageProtectedAccess;
		}

		public Object setup(Map context, Object target, Member member, String propertyName) {
			Object result = null;

			if (isAccessible(context, target, member, propertyName)) {
				AccessibleObject accessible = (AccessibleObject) member;

				if (!accessible.isAccessible()) {
					result = Boolean.FALSE;
					accessible.setAccessible(true);
				}
			}
			return result;
		}

		public void restore(Map context, Object target, Member member, String propertyName, Object state) {
			if (state != null) {
				((AccessibleObject) member).setAccessible(((Boolean) state).booleanValue());
			}
		}

		public boolean isAccessible(Map context, Object target, Member member, String propertyName) {
			int modifiers = member.getModifiers();
			boolean result = Modifier.isPublic(modifiers);

			if (!result) {
				if (Modifier.isPrivate(modifiers)) {
					result = getAllowPrivateAccess();
				} else {
					if (Modifier.isProtected(modifiers)) {
						result = getAllowProtectedAccess();
					} else {
						result = getAllowPackageProtectedAccess();
					}
				}
			}
			return result;
		}
	}

}